#pragma once

#include <iostream>

using namespace std;

#define NULL 0


enum NodeType
{
	HEAD,
	TAIL,
	NORMAL
};

template<typename D>
class Node
{
public:
	Node(NodeType nodeType, D data) {
		setNodeType(nodeType);
		setData(data);
		prev = NULL;
		next = NULL;
	};
	Node(NodeType nodeType, D data, Node* prev, Node* next) {
		setNodeType(nodeType);
		setData(data);
		setPrev(prev);
		setNext(next);
	};
	~Node() {}

	D getData() { return data; }
	void setData(D data) { this->data = data; }
	Node* getPrev() { return prev; }
	void setPrev(Node* prev) { this->prev = prev; }
	Node* getNext() { return next; }
	void setNext(Node* next) { this->next = next; }
	NodeType getNodeType() { return nodeType; }
	void setNodeType(NodeType nodeType) { this->nodeType = nodeType; }

	void printString() {
		cout << "Node {" << endl;
		cout << "\tNodeType : " << reflectNodeType(nodeType) << endl;
		cout << "\tdata = " << data << endl;
		cout << "\tprev = " << prev->getData() << endl;
		cout << "\tnext = " << next->getData() << endl;
		cout << "}" << endl;
	}

	void printLine() {
		cout << "Node {";
		cout << " NodeType : " << reflectNodeType(nodeType);
		cout << " data = " << data;
		cout << " prev = " << prev->getData();
		cout << " next = " << next->getData();
		cout << " }" << endl;
	}

private:
	Node* prev;
	Node* next;
	D data;
	NodeType nodeType;

	string reflectNodeType(NodeType nodeType) {
		switch (nodeType)
		{
		case HEAD:
			return "HEAD";
			break;
		case TAIL:
			return "TAIL";
			break;
		case NORMAL:
			return "NORMAL";
			break;
		default:
			return "NULL";
			break;
		}
	}
};
